import { Option, OptionSelection, OptionSelections, ProductVariant } from "@mallfoundry/catalog"
import { Form, InputNumber, Table } from "antd"
import { ColumnProps } from "antd/lib/table"
import * as _ from "lodash"
import * as React from "react"
import classes from "./product-variants.module.scss"


interface CrossedValue {
  optionSelections: OptionSelection[];
  inventoryQuantity: number;
  price: number;
  weight: number;

  [key: string]: any;
}

function createOptionSelection(nameId?: string, name?: string, valueId?: string, value?: string) {
  const selection = new OptionSelection()
  selection.nameId = nameId
  selection.name = name
  selection.valueId = valueId
  selection.value = value
  return selection
}

function crossOptions(crossedValues: CrossedValue[], option2: Option): CrossedValue[] {
  return _.flatMap(crossedValues, crossedValue => {
    return _.map(option2.values, value2 => {
      return {
        ...crossedValue,
        [option2.name as string]: value2.label,
        optionSelections: [...crossedValue.optionSelections, createOptionSelection(option2.id, option2.name, value2.id, value2.label)],
      }
    })
  })
}

function crossOption(option: Option): CrossedValue[] {
  return _.map(option.values, value => {
    return {
      [option.name as string]: value.label,
      optionSelections: [createOptionSelection(option.id, option.name, value.id, value.label)],
      inventoryQuantity: 0,
      price: 0,
      weight: 0,
    }
  })
}

function createCrossedValues(options: Option[], variants: ProductVariant[]) {

  if (_.isEmpty(options)) {
    return []
  }

  let crossedValues = crossOption(_.first(options) as Option)
  const options2 = _.slice(options, 1)
  for (const option2 of options2) {
    crossedValues = crossOptions(crossedValues, option2)
  }

  for (const variant of variants) {
    const crossedValue = _.find(crossedValues, crossedValue => OptionSelections.equals(crossedValue.optionSelections, variant.optionSelections))
    if (crossedValue) {
      crossedValue.price = variant.price as number
      crossedValue.inventoryQuantity = variant.inventoryQuantity as number
      crossedValue.weight = variant.weight as number
    }
  }
  crossedValues = _.map(crossedValues, crossedValue => ({
    ...crossedValue,
    key: _.reduce(crossedValue.optionSelections, (optionString, selection) => {
      return optionString + `${selection.name}:${selection.value}`
    }, ""),
  }))
  return crossedValues
}

export function createVariants(options: Option[], variants: ProductVariant[] = []) {
  const crossedValues = createCrossedValues(options, variants)
  return _.map(crossedValues, crossedValue => {
    const variant = new ProductVariant()
    variant.optionSelections = crossedValue.optionSelections
    variant.price = crossedValue.price
    variant.inventoryQuantity = crossedValue.inventoryQuantity
    variant.weight = crossedValue.weight
    return variant
  })
}

function crossedValuesToVariants(values: CrossedValue[], variants: ProductVariant[]) {
  return _.map(values, crossedValue => {
    const oldVariant = _.find(variants, variant => OptionSelections.equals(variant.optionSelections, crossedValue.optionSelections))
    return _.assign(new ProductVariant(), oldVariant, {
      optionSelections: crossedValue.optionSelections,
      price: crossedValue.price,
      inventoryQuantity: crossedValue.inventoryQuantity,
      weight: crossedValue.weight,
    })
  })
}

interface ProductVariantsProps {
  options: Option[];
  variants: ProductVariant[];
  onChange: (variants: ProductVariant[]) => void;
}

export default function ProductVariants(props: ProductVariantsProps) {
  const { options, variants, onChange } = props
  /*  const optionsIds = _.chain(options)
      .transform((optionsIds: string[], option: Option) => {
        optionsIds.push(option.name as string)
        optionsIds.push(_.chain(option.values).map(value => value.label).join().value())
      }, []).join().value()
    console.log(optionsIds)*/

  const dataSource = createCrossedValues(options, variants)

  function optionsColumns() {
    return _.map(options, (option) => ({
      title: option.name,
      dataIndex: option.name,
      key: option.name,
    }))
  }

  function changeVariants() {
    onChange(crossedValuesToVariants(dataSource, variants))
  }

  function createInputColumn(column: ColumnProps<CrossedValue>) {
    const { render, ...restColumn } = column
    return {
      ...restColumn,
      render: (text: number, record: CrossedValue) => {
        function changeValue(e: React.KeyboardEvent<HTMLInputElement> | React.FocusEvent<HTMLInputElement>) {
          if (column.key) {
            const valueNumber = _.toNumber(e.currentTarget.value)
            if (record[column.key] !== valueNumber) {
              record[column.key] = valueNumber
              changeVariants()
            }
          }
        }

        return <Form.Item style={{ marginBottom: "0" }}>
          <InputNumber defaultValue={text} style={{ width: "100%" }} min={column.key === "price" ? 0.01 : 0}
                       precision={column.key === "inventoryQuantity" ? 0 : 2}
                       onPressEnter={changeValue} onBlur={changeValue}/>
        </Form.Item>
      },
    }
  }

  const columns = [
    ...optionsColumns(),
    createInputColumn({
      key: "price",
      dataIndex: "price",
      title: "价格",
      width: "120px",
    }),
    createInputColumn({
      key: "inventoryQuantity",
      dataIndex: "inventoryQuantity",
      title: "库存",
      width: "120px",
    }),
    createInputColumn({
      key: "weight",
      dataIndex: "weight",
      title: "重量(KG)",
      width: "120px",
    })]
  return <Table className={classes.productVariants} bordered
                columns={columns} dataSource={dataSource}
                size="middle" pagination={false}/>
}
